#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <wait.h>

#define AGGREGATE_STATS_OP_CLONE 0
#define AGGREGATE_STATS_OP_MAX   1
#include "aggregate_stats.h"

void usage() {
	fprintf(stderr, "heavensgate -s numspawners -n numspawns\n");
	exit(0);
}

int fn(int i) {
	exit(0);
}

void spawn(int times) {
	int i;
	int ret;
	char *stack;
	char *stackptr;

	stack = (char *)malloc(4096);
	stackptr = stack + 4095;

	for (i = 0 ; i < times ; i++) {
		AGGREGATE_STATS_DO(ret = clone((void *)fn, (void *)stackptr, 0, 0),
			AGGREGATE_STATS_OP_CLONE);
		if (ret == -1) {
			perror("clone");
			exit(1);
		}
		if (ret == 0)
			exit(0);
	}
}

int main(int argc, char *argv[])
{
	int c;
	int ret;
	int psindex;
	int numspawns = 0;
	int numspawners = 1;

	AGGREGATE_STATS_INIT;

	if (argc != 5)
		usage();

	while((c = getopt(argc, argv, "s:n:")) != -1) {
		switch(c) {
			case 's':
				if (!optarg) usage();
					numspawners = atoi(optarg);
				break;
			case 'n':
				if (!optarg) usage();
					numspawns = atoi(optarg);
				break;
		}
	}

	if (numspawns < 0) {
		fprintf(stderr, "number of spawns must be >= 0\n");
		usage();
	}

	if (numspawners <= 0) {
		fprintf(stderr, "number of spawners must be > 0\n");
		usage();
	}

	for (c = 1, psindex = 1 ; c < numspawners ; c++, psindex++) {
		ret = fork();
		if (ret == -1) {
			perror("fork");
			exit(1);
		}
		if (ret == 0) {
			spawn(numspawns);
			for (c = 0 ; c < numspawns ; c++)
				waitpid(-1, NULL, 0);
			exit(0);
		}
	}

	spawn(numspawns);
	for (c = 0 ; c < numspawns ; c++)
		waitpid(-1, NULL, 0);

	AGGREGATE_STATS_PRINT;
	return 0;
}
